package codec

import (
	"bufio"
	"encoding/gob"
	"io"
	"log"
)

var _ Codec = (*GobCodec)(nil)

// GobCodec 结构体
type GobCodec struct {
	conn io.ReadWriteCloser // 由构建函数传入，通常是通过 TCP 或者 Unix 建立 socket 时得到的链接实例
	buf  *bufio.Writer      // 为了防止阻塞而创建的带缓冲的 Writer，一般这么做能提升性能
	dec  *gob.Decoder
	enc  *gob.Encoder
}

func NewGobCodec(conn io.ReadWriteCloser) Codec {
	buf := bufio.NewWriter(conn)
	return &GobCodec{
		conn: conn,
		buf:  buf,
		dec:  gob.NewDecoder(conn),
		enc:  gob.NewEncoder(buf),
	}
}

// Close 关闭链接
func (c *GobCodec) Close() error {
	return c.conn.Close()
}

// ReadHeader 读取请求头
func (c *GobCodec) ReadHeader(h *Header) error {
	return c.dec.Decode(h)
}

// ReadBody 读取body
func (c *GobCodec) ReadBody(body interface{}) error {
	return c.dec.Decode(body)
}

// Write 响应数据
func (c *GobCodec) Write(h *Header, body interface{}) (err error) {
	defer func() {
	   _ = c.buf.Flush() // 释放缓存
	   if err != nil {
	   		_ = c.Close()
	   }
	}()

	if err = c.enc.Encode(h); err != nil {
	    log.Println("rpc codec: gob error encoding header:", err)
	    return
	}

	if err = c.enc.Encode(body); err != nil {
		log.Println("rpc codec: gob error encoding body:", err)
		return
	}

	return
}
